// Copyright (c) 2025 Huawei Technologies Co., Ltd.
// openUBMC is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
//         http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
//
// Description: scsi命令处理

#include "ScsiProcessor.hpp"

ScsiProcessor::ScsiProcessor(ImageDevice& imageDevice)
    : imageDevice_(imageDevice),
      dataBuffer_(READ_BUFFER_SIZE, 0) {}

ScsiProcessor::~ScsiProcessor() = default;

void ScsiProcessor::SetSendHandler(std::function<void(const std::vector<uint8_t>&)> handler) {
    sendHandler_ = std::move(handler);
}

void ScsiProcessor::SetLogHandler(std::function<void(const std::string&)> handler) {
    logHandler_ = std::move(handler);
}

// 设置设备的状态位
void ScsiProcessor::SetSenseKey(uint8_t senseKey, uint8_t asc, uint8_t ascq, int info) {
    if (info == 0) {
        senseKey_[0] = 0x70;    // 响应码：当前错误（0x70 表示固定格式的 Sense Data）
        senseKey_[3] = 0;       // info字段高8位
        senseKey_[4] = 0;       // info字段次高8位
        senseKey_[5] = 0;       // info字段次低8位
        senseKey_[6] = 0;       // info字段低8位
    } else {
        senseKey_[0] = 0xf0;    // 响应码：已修正错误（0xf0 表示固定格式的 Sense Data）
        senseKey_[3] = (info >> 24) & 0xff;     // info字段高8位
        senseKey_[4] = (info >> 16) & 0xff;     // info字段次高8位
        senseKey_[5] = (info >> 8) & 0xff;      // info字段次低8位
        senseKey_[6] = info & 0xff;             // info字段低8位
    }
    senseKey_[2] = senseKey;    // Sense Key：指示错误类型（例如 NO_SENSE、NOT_READY 等）
    senseKey_[12] = asc;        // Additional Sense Code 附加感知码（ASC）：提供详细的错误信息
    senseKey_[13] = ascq;       // Additional Sense Code Qualifier 附加感知码限定符（ASCQ）：进一步限定 ASC 的含义
}

void ScsiProcessor::SendData(const std::vector<uint8_t>& data, int dataLength, bool isLast) {
    int pos = 0;
    int curLength = 0;
    std::vector<uint8_t> dataPack;

    if (dataLength == 0 && isLast) {
        dataPack = PackData().SffDataPack(ScsiDataType::DATA, ScsiDataState::END, dataLength, cmdId);
        sendHandler_(dataPack);
    }

    while (dataLength > 0) {
        if (dataLength > MAX_PACKET_SIZE) {
            curLength = MAX_PACKET_SIZE;
            dataPack = PackData().SffDataPack(ScsiDataType::DATA, ScsiDataState::CONTINUE, curLength, cmdId);
        } else {
            curLength = dataLength;
            if (isLast) {
                dataPack = PackData().SffDataPack(ScsiDataType::DATA, ScsiDataState::END, curLength, cmdId);
            } else {
                dataPack = PackData().SffDataPack(ScsiDataType::DATA, ScsiDataState::CONTINUE, curLength, cmdId);
            }
        }

        // SffDataPack封装时已申请了对应curLength大小的内存空间，因此可以直接拷贝
        std::copy(data.begin() + pos, data.begin() + pos + curLength, dataPack.begin() + PACKET_HEAD_SIZE);
        
        sendHandler_(dataPack);

        pos += curLength;
        dataLength -= curLength;
    }
}

void ScsiProcessor::CommandFinish(uint8_t cmd) {
    uint8_t result = 0;
    // 第2位为Sense Key指示错误类型
    if ((senseKey_[2] != 0 && cmd != ScsiCommand::REQUEST_SENSE) ||
        (cmd == ScsiCommand::TEST_UNIT_READY_EXP)) {
        result = 1;
    }
    sendHandler_(PackData().SffOperationEnd(result, cmdId));
}

void ScsiProcessor::TestUnitReady() {
    DeviceState state = imageDevice_.TestUnitReady();
    switch (state) {
        case DeviceState::MEDIUM_CHANGE:
            imageDevice_.SetDeviceState(DeviceState::MEDIUM_CHANGE);
            SetSenseKey(ScsiSenseKey::UNIT_ATTENTION, ScsiAsc::MEDIUM_CHANGE, 0, 0);
            readErrNum = 0;
            break;
        case DeviceState::READY:
            imageDevice_.SetDeviceState(DeviceState::READY);
            SetSenseKey(ScsiSenseKey::NO_SENSE, ScsiAsc::NO_ADDITIONAL_SENSE, 0, 0);
            break;
        case DeviceState::BAD_MEDIA:
            imageDevice_.SetDeviceState(DeviceState::BAD_MEDIA);
            SetSenseKey(ScsiSenseKey::NOT_READY, ScsiAsc::INCOMPATIBLE_MEDIUM_INSTALLED, 0, 0);
            readErrNum = 0;
            break;
        case DeviceState::NOT_READY:
            imageDevice_.SetDeviceState(DeviceState::NOT_READY);
            SetSenseKey(ScsiSenseKey::NOT_READY, ScsiAsc::LOGICAL_UNIT_NOT_READY, 0, 0);
            readErrNum = 0;
            break;
        case DeviceState::NOT_PRESENT:
        default:
            imageDevice_.SetDeviceState(DeviceState::NOT_PRESENT);
            SetSenseKey(ScsiSenseKey::NOT_READY, ScsiAsc::MEDIUM_NOT_PRESENT, 0, 0);
            readErrNum = 0;
            break;
    }
}

void ScsiProcessor::StartStop(const std::vector<uint8_t>& data) {
    bool isEject = false;
    bool isStart = false;

    // 检查 CDB 的第 4 字节的位 1（0x02）：是否为弹出操作
    if ((data[4] & 0x02) == 0x02) {
        isEject = true;
    }

    // 检查 CDB 的第 4 字节的位 0（0x01）：是否为启动操作
    if ((data[4] & 0x01) == 0x01) {
        isStart = true;
    }

    if (!isStart && isEject) {
        imageDevice_.SetDeviceState(DeviceState::NOT_PRESENT);
    } else if (isStart && !isEject) {
        imageDevice_.SetDeviceState(DeviceState::READY);
    }
    SetSenseKey(ScsiSenseKey::NO_SENSE, ScsiAsc::NO_ADDITIONAL_SENSE, 0, 0);
}

void ScsiProcessor::ModeSense(const std::vector<uint8_t>& data) {
    // 从 CDB 的第 2 字节提取 PC（Page Control，页控制）字段（高 2 位）
    uint8_t pc = (data[2] >> 6) & 0xff;
    // 从 CDB 的第 2 字节提取 Page Code（页码）字段（低 6 位）
    uint8_t pageCode = data[2] & 0x3f;

    std::vector<uint8_t> modeSenseData(MODE_SENSE_DATA_SIZE);
    modeSenseData[0] = 0;   // Mode Data Length（模式数据长度，高字节，固定为 0）
    modeSenseData[1] = 6;   // Mode Data Length（模式数据长度，低字节，固定为 6）
    modeSenseData[2] = (imageDevice_.TestUnitReady() != DeviceState::NOT_PRESENT) ? 1 : 0x70; // 设备状态，0x70表示设备不可用
    modeSenseData[3] = 0;   // Reserved
    modeSenseData[4] = 0;   // Reserved
    modeSenseData[5] = 0;   // Reserved
    modeSenseData[6] = 0;   // Reserved
    modeSenseData[7] = 0;   // Reserved

    SetSenseKey(ScsiSenseKey::NO_SENSE, ScsiAsc::NO_ADDITIONAL_SENSE, 0, 0);
    SendData(modeSenseData, MODE_SENSE_DATA_SIZE, true);
}

void ScsiProcessor::Read(const std::vector<uint8_t>& data) {
    unsigned long long lba = (data[2] << 24) | (data[3] << 16) | (data[4] << 8) | data[5];  // 4字节Logical Block Address (LBA)
    int blockNum = 0;

    if (data[0] == ScsiCommand::READ_10) {
        blockNum = (data[7] << 8) | data[8];            // READ_10命令读取块数量为2字节
    } else {
        blockNum = (data[6] << 24) | (data[7] << 16) | (data[8] << 8) | data[9];    // READ_12命令读取块数量为4字节
    }

    int length = blockNum * BLOCK_LENGTH;
    
    // 如果在cache命中则直接取缓存中的数据发送，否则先读出来再发送
    if (cacheBlockNum != 0 && cacheBlockNum == blockNum && cacheLba != 0 && cacheLba == lba) {
        SendData(dataBuffer_, length, true);
        SetSenseKey(ScsiSenseKey::NO_SENSE, ScsiAsc::NO_ADDITIONAL_SENSE, 0, 0);
    } else {
        int curRead = ReadBlockData(lba, blockNum, false);
        if (curRead <= 0) {
            return;
        }
        SendData(dataBuffer_, curRead, true);
        SetSenseKey(ScsiSenseKey::NO_SENSE, ScsiAsc::NO_ADDITIONAL_SENSE, 0, 0);
    }
    cacheBlockNum = blockNum;
    cacheLba = lba + blockNum;
    ReadBlockData(cacheLba, cacheBlockNum, true);
}

int ScsiProcessor::ReadBlockData(unsigned long long lba, int blockNum, bool cache) {
    unsigned long long startPos = lba * BLOCK_LENGTH;
    int length = blockNum * BLOCK_LENGTH;
    int curRead = 0;

    if (readErrNum >= READ_ERR_LIMIT && readErrAreaBegin <= lba && readErrAreaEnd > lba) {
        if (!cache) {
            SetSenseKey(ScsiSenseKey::MEDIUM_ERROR, ScsiAsc::ID_CRC_OR_ECC_ERROR, 0, static_cast<int>(startPos / BLOCK_LENGTH));
        }
        cacheBlockNum = 0;
        cacheLba = 0;
        return 0;
    }

    if (startPos >= 0 && startPos < imageDevice_.GetFileSize()) {
        int readLength = (length > READ_BUFFER_SIZE) ? READ_BUFFER_SIZE : length;

        try {
            curRead = imageDevice_.ReadData(dataBuffer_, startPos, readLength);
        } catch(const std::exception& e) {
            cacheBlockNum = 0;
            cacheLba = 0;
            readErrNum++;
            readErrAreaBegin = lba;
            readErrAreaEnd = lba + blockNum;
            logHandler_("ReadBlockData error: " + std::string(e.what()));
            return 0;
        }

        if (curRead == readLength) {
            length -= readLength;
        } else {
            length = -1;
        }

        if (length == 0) {
            if (!cache) {
                SetSenseKey(ScsiSenseKey::NO_SENSE, ScsiAsc::NO_ADDITIONAL_SENSE, 0, 0);
            }
        } else {
            if (!cache) {
                SetSenseKey(ScsiSenseKey::ILLEGAL_REQUEST, ScsiAsc::LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE, 0, 0);
            }
            cacheBlockNum = 0;
            cacheLba = 0;
        }
        readErrNum = 0; // 重置读取错误计数
    } else {
        if (!cache) {
            SetSenseKey(ScsiSenseKey::ILLEGAL_REQUEST, ScsiAsc::LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE, 0, 0);
        }
        cacheBlockNum = 0;
        cacheLba = 0;
    }

    return curRead;
}

int ScsiProcessor::ReadTocFormat0(std::vector<uint8_t>& tocData, bool isMSF, int startTrack) {
    // 检查起始轨道是否有效，起始轨道必须为 1 或 0xaa（Lead-out Track）
    if (startTrack > 1 && startTrack != 0xaa) {
        return -1; // 无效的起始轨道
    }

    // TOC 数据的第 2 和第 3 字节固定为 1，表示第一会话和最后会话的轨道号
    tocData[2] = 1;     // 第一会话的起始轨道号
    tocData[3] = 1;     // 最后一会话的结束轨道号

    int len = 4;        // TOC 数据的起始长度为 4 字节（前 4 字节为头部信息）
    int totalBlocks = imageDevice_.GetFileSize() / BLOCK_LENGTH;
    int blocks = totalBlocks + 150;         // 加上 150 块的 Lead-in 区域
    int blockFrames = blocks / 75;          // 每帧 75 块
    uint8_t minutes = blockFrames / 60;     // 分钟
    uint8_t seconds = blockFrames % 60;     // 秒
    uint8_t frames = blocks % 75;           // 帧

    // 如果起始轨道为 1 或更小，添加第一轨道的 TOC 信息
    if (startTrack <= 1) {
        tocData[len++] = 0;     // Reserved（保留字段，固定为 0）
        tocData[len++] = 20;    // ADR 和 Control 字段，20 表示数据轨道
        tocData[len++] = 1;     // 第一轨道的轨道号
        tocData[len++] = 0;     // Reserved（保留字段，固定为 0）
        tocData[len++] = 0;     // address 4字节高位
        tocData[len++] = 0;     // address 4字节次高位
        tocData[len++] = isMSF ? 2 : 0;     // address 4字节次低位，MSF 模式下为 2，否则为 0
        tocData[len++] = 0;     // address 4字节低位
    }

    // 添加 Lead-out Track 的 TOC 信息
    tocData[len++] = 0;     // reserved1
    tocData[len++] = 20;    // adrControl
    tocData[len++] = 0xaa;  // trackNumber
    tocData[len++] = 0;     // reserved2
    if (!isMSF) {
        tocData[len++] = (totalBlocks >> 24) & 0xff;    // address 4字节高位
        tocData[len++] = (totalBlocks >> 16) & 0xff;    // address 4字节次高位
        tocData[len++] = (totalBlocks >> 8) & 0xff;     // address 4字节次低位
        tocData[len++] = totalBlocks & 0xff;            // address 4字节低位
    } else {
        tocData[len++] = 0;         // Reserved（保留字段，固定为 0）
        tocData[len++] = minutes;
        tocData[len++] = seconds;
        tocData[len++] = frames;
    }

    // 设置 TOC 数据的长度字段（前 2 字节）
    tocData[0] = ((len - 2) >> 8) & 0xff;   // length高字节
    tocData[1] = (len - 2) & 0xff;          // length低字节

    return len;
}

int ScsiProcessor::ReadTocFormat1(std::vector<uint8_t>& tocData) {
    tocData[2] = 1;         // 第一会话的起始轨道号
    tocData[3] = 1;         // 最后一会话的结束轨道号

    int len = 4;
    tocData[len++] = 0;     // reserved1
    tocData[len++] = 0;     // adrControl
    tocData[len++] = 0;     // trackNumber
    tocData[len++] = 0;     // reserved2
    tocData[len++] = 0;     // address 4字节高位
    tocData[len++] = 0;     // address 4字节次高位
    tocData[len++] = 0;     // address 4字节次低位
    tocData[len++] = 0;     // address 4字节低位

    // 设置 TOC 数据的长度字段（前 2 字节）
    tocData[0] = ((len - 2) >> 8) & 0xff;   // length高字节
    tocData[1] = (len - 2) & 0xff;          // length低字节

    return len;
}

int ScsiProcessor::ReadTocFormat2(std::vector<uint8_t>& tocData, bool isMSF) {
    tocData[2] = 1;         // 第一会话的起始轨道号
    tocData[3] = 1;         // 最后一会话的结束轨道号

    int len = 4;
    size_t fileSize = imageDevice_.GetFileSize();
    int totalBlocks = fileSize / BLOCK_LENGTH;
    int blocks = totalBlocks + 150;         // 加上 150 块的 Lead-in 区域
    int blockFrames = blocks / 75;          // 每帧 75 块
    uint8_t minutes = blockFrames / 60;     // 分钟
    uint8_t seconds = blockFrames % 60;     // 秒
    uint8_t frames = blocks % 75;           // 帧

    for (int i = 0; i < 4; i++) {
        tocData[len++] = 1;         // sessionNumber，表示会话号，固定为 1
        tocData[len++] = 0x14;      // adrControl，ADR 和 Control 字段，0x14 表示数据轨道
        tocData[len++] = 0;         // tno，轨道号，固定为 0
        tocData[len++] = (i < 3) ? (0xa0 + i) : 1;      // point，0xa0 表示会话信息，0xa1 表示第一轨道，0xa2 表示最后轨道
        tocData[len++] = 0;         // min，分钟，固定为 0
        tocData[len++] = 0;         // sec，秒，固定为 0
        tocData[len++] = 0;         // frame，帧，固定为 0

        if (i == 2) {
            // 如果是最后轨道（point = 0xa2）
            if (!isMSF) {
                // 如果不是 MSF 模式，使用块地址
                tocData[len++] = (totalBlocks >> 24) & 0xff;    // address 4字节高位
                tocData[len++] = (totalBlocks >> 16) & 0xff;    // address 4字节次高位
                tocData[len++] = (totalBlocks >> 8) & 0xff;     // address 4字节次低位
                tocData[len++] = totalBlocks & 0xff;            // address 4字节低位
            } else {
                // 如果是 MSF 模式，使用分钟、秒和帧
                tocData[len++] = 0;
                tocData[len++] = minutes;
                tocData[len++] = seconds;
                tocData[len++] = frames;
            }
        } else {
            // 如果不是最后轨道
            tocData[len++] = 0;         // zero
            tocData[len++] = (i < 2) ? 1 : 0;         // pmin，第一轨道为 1，其他为 0
            tocData[len++] = 0;         // psec
            tocData[len++] = 0;         // pframe
        }
    }

    // 设置 TOC 数据的长度字段（前 2 字节）
    tocData[0] = ((len - 2) >> 8) & 0xff;   // length高字节
    tocData[1] = (len - 2) & 0xff;          // length低字节

    return len;
}

void ScsiProcessor::ReadToc(const std::vector<uint8_t>& data) {
    bool isMSF = ((data[1] & 0x02) == 2);   // 检查是否为 MSF 模式（分钟-秒-帧格式）
    int format = data[2] & 0x07;            // 提取 TOC 格式（低 3 位）
    if (format == 0) {
        format = ((data[9] >> 6) & 0x03);   // 如果格式为 0，则从第 9 字节的高 2 位提取格式
    }
    int allocationLength = (data[7] << 8) | (data[8] & 0xff);   // 分配长度（第 7 和第 8 字节，2 字节）
    int startTrack = data[6];               // 起始轨道号（第 6 字节）
    std::vector<uint8_t> tocData(MAX_TOC_DATA_SIZE);
    int tocDataLength = 0;
    switch (format) {
        case 0:
            tocDataLength = ReadTocFormat0(tocData, isMSF, startTrack);
            break;
        case 1:
            tocDataLength = ReadTocFormat1(tocData);
            break;
        case 2:
            tocDataLength = ReadTocFormat2(tocData, isMSF);
            break;
        default:
            break;
    }
    SetSenseKey(ScsiSenseKey::NO_SENSE, ScsiAsc::NO_ADDITIONAL_SENSE, 0, 0);

    if (tocDataLength > allocationLength) {
        tocDataLength = allocationLength;
    }
    
    SendData(tocData, tocDataLength, true);
}

void ScsiProcessor::ReadCapacity() {
    DeviceState deviceState = imageDevice_.TestUnitReady();
    size_t fileSize = 0;
    std::vector<uint8_t> readCapacityData(8);
    unsigned long long lba = 0;

    switch (deviceState) {
        case DeviceState::NOT_PRESENT:
            SetSenseKey(ScsiSenseKey::NOT_READY, ScsiAsc::MEDIUM_NOT_PRESENT, 0, 0);
            break;
        case DeviceState::MEDIUM_CHANGE:
            SetSenseKey(ScsiSenseKey::UNIT_ATTENTION, ScsiAsc::MEDIUM_CHANGE, 0, 0);
            break;
        case DeviceState::READY:
            fileSize = imageDevice_.GetFileSize();
            if (fileSize < 0) {
                SetSenseKey(ScsiSenseKey::NOT_READY, ScsiAsc::MEDIUM_NOT_PRESENT, 0, 0);
                break;
            }
            lba = fileSize / BLOCK_LENGTH - 1;
            readCapacityData[0] = (lba >> 24) & 0xff;           // Logical Block Address 高8位
            readCapacityData[1] = (lba >> 16) & 0xff;           // Logical Block Address 次高8位
            readCapacityData[2] = (lba >> 8) & 0xff;            // Logical Block Address 次低8位
            readCapacityData[3] = lba & 0xff;                   // Logical Block Address 低8位
            readCapacityData[4] = (BLOCK_LENGTH >> 24) & 0xff;  // Logical Block Length 高8位
            readCapacityData[5] = (BLOCK_LENGTH >> 16) & 0xff;  // Logical Block Length 次高8位
            readCapacityData[6] = (BLOCK_LENGTH >> 8) & 0xff;   // Logical Block Length 次低8位
            readCapacityData[7] = BLOCK_LENGTH & 0xff;          // Logical Block Length 低8位

            SetSenseKey(ScsiSenseKey::NO_SENSE, ScsiAsc::NO_ADDITIONAL_SENSE, 0, 0);
            SendData(readCapacityData, readCapacityData.size(), true);
            break;
        default:
            break;
    }
}

void ScsiProcessor::ReadFormatCapacity() {
    // 读取格式化容量的实现
    if (imageDevice_.TestUnitReady() == DeviceState::MEDIUM_CHANGE) {
        imageDevice_.SetDeviceState(DeviceState::READY);
        SetSenseKey(ScsiSenseKey::UNIT_ATTENTION, ScsiAsc::MEDIUM_CHANGE, 0, 0);
    } else {
        SetSenseKey(ScsiSenseKey::NO_SENSE, ScsiAsc::NO_ADDITIONAL_SENSE, 0, 0);
    }

    size_t fileSize = imageDevice_.GetFileSize();
    if (fileSize < 0) {
        return;
    }
    int totalBlocks = fileSize / BLOCK_LENGTH;
    formatCapacityData_[4] = (totalBlocks >> 24) & 0xff;    // Logical Block Address 高8位
    formatCapacityData_[5] = (totalBlocks >> 16) & 0xff;    // Logical Block Address 次高8位
    formatCapacityData_[6] = (totalBlocks >> 8) & 0xff;     // Logical Block Address 次低8位
    formatCapacityData_[7] = totalBlocks & 0xff;            // Logical Block Address 低8位
    formatCapacityData_[9] = (BLOCK_LENGTH >> 16) & 0xff;   // Logical Block Length 次高8位
    formatCapacityData_[10] = (BLOCK_LENGTH >> 8) & 0xff;   // Logical Block Length 次低8位
    formatCapacityData_[11] = BLOCK_LENGTH & 0xff;          // Logical Block Length 低8位
    SendData(formatCapacityData_, formatCapacityData_.size(), true);
}

void ScsiProcessor::ProcessScsiCommand(VMMMessage vmmMsg) {
    cmdId = vmmMsg.GetSeq();
    std::vector<uint8_t> data = vmmMsg.GetData();
    uint8_t scsiCmd = data[0];

    switch (scsiCmd) {
        case ScsiCommand::INQUIRY:
            SendData(inquiryData_, inquiryData_.size(), true);
            SetSenseKey(ScsiSenseKey::NO_SENSE, ScsiAsc::NO_ADDITIONAL_SENSE, 0, 0);
            break;
        case ScsiCommand::REQUEST_SENSE:
            SendData(senseKey_, senseKey_.size(), true);
            break;
        case ScsiCommand::MODE_SENSE:
            ModeSense(data);
            break;
        case ScsiCommand::READ_CAPACITY:
            ReadCapacity();
            break;
        case ScsiCommand::READ_FORMAT_CAPACITY:
            ReadFormatCapacity();
            break;
        case ScsiCommand::READ_10:
        case ScsiCommand::READ_12:
            Read(data);
            break;
        case ScsiCommand::READ_TOC:
            ReadToc(data);
            break;
        case ScsiCommand::START_STOP:
            StartStop(data);
            break;
        case ScsiCommand::TEST_UNIT_READY:
        case ScsiCommand::TEST_UNIT_READY_EXP:
            TestUnitReady();
            break;
        case ScsiCommand::FORMAT_UNIT:
            SetSenseKey(ScsiSenseKey::DATA_PROTECT, ScsiAsc::WRITE_PROTECTED, 0, 0);
            break;
        case ScsiCommand::MODE_SELECT:
        case ScsiCommand::PREVENT_ALLOW_MEDIUM_REMOVAL:
        case ScsiCommand::SEEK_10:
        case ScsiCommand::SEND_DIAGNOSTIC:
        case ScsiCommand::REZERO_UNIT:
        case ScsiCommand::VERIFY:
            SetSenseKey(ScsiSenseKey::NO_SENSE, ScsiAsc::NO_ADDITIONAL_SENSE, 0, 0);
            break;
        default:
            SetSenseKey(ScsiSenseKey::ILLEGAL_REQUEST, ScsiAsc::INVALID_FIELD_IN_CDB, 0, 0);
            break;
    }

    CommandFinish(scsiCmd);
}
